package com.drawingtimer.admin.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.fill.FillConfig;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.drawingtimer.admin.config.erp.ErpConfigProperties;
import com.drawingtimer.admin.model.entity.TProcessFlowCard;
import com.drawingtimer.admin.model.entity.TProcessInfo;
import com.drawingtimer.admin.model.vo.TPrdMoVO;
import com.drawingtimer.admin.model.vo.TProcessFlowCardPageVO;
import com.drawingtimer.admin.model.qo.TProcessFlowCardQO;
import com.drawingtimer.admin.mapper.TProcessFlowCardMapper;
import com.drawingtimer.admin.model.vo.TProcessInfoPageVO;
import com.drawingtimer.admin.model.vo.TProcessInfoVO;
import com.drawingtimer.admin.service.TProcessFlowCardService;
import com.drawingtimer.admin.utils.http.HTTP;
import com.drawingtimer.admin.utils.sign.ErpSign;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.hccake.ballcat.common.model.domain.PageParam;
import com.hccake.ballcat.common.model.domain.PageResult;
import com.hccake.extend.mybatis.plus.service.impl.ExtendServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 工序流转卡信息
 *
 * @author jjh 2025-04-24 16:34:16
 */
@Service
@Slf4j
public class TProcessFlowCardServiceImpl extends ExtendServiceImpl<TProcessFlowCardMapper, TProcessFlowCard>
		implements TProcessFlowCardService {

	@Autowired
	private TProcessInfoServiceImpl tProcessInfoService;

	@Autowired
	private HTTP http;

	@Autowired
	private RedisTemplate redisTemplate;

	@Autowired
	private ErpConfigProperties erpConfig;

	public static String HOST = "http://192.168.10.241";

	public static String LOGIN_URI = "/K3Cloud/Kingdee.BOS.WebApi.ServicesStub.AuthService.LoginBySign.common.kdsvc";

	public static String GET_PROCESS_INFO_BY_FLOW_CARD_URI = "/K3Cloud/Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.ExecuteBillQuery.common.kdsvc";

	public static String GET_KEY_VALUE_JSON_URI = "/K3Cloud/Kingdee.BOS.WebApi.ServicesStub.DynamicFormService.BillQuery.common.kdsvc";

	/**
	 * 根据QueryObeject查询分页数据
	 * @param pageParam 分页参数
	 * @param qo 查询参数对象
	 * @return PageResult<TProcessFlowCardPageVO> 分页数据
	 */
	@Override
	public PageResult<TProcessFlowCardPageVO> queryPage(PageParam pageParam, TProcessFlowCardQO qo) {
		return baseMapper.queryPage(pageParam, qo);
	}

	@Override
	public PageResult<TProcessInfoPageVO> getDetailsById(String flowCardNumber) {
		return tProcessInfoService.getDetailsByFlowCardNumber(flowCardNumber);

	}

	@Override
	public void export(Long id, HttpServletResponse response) {

		response.setContentType("application/vnd.ms-excel");
		response.setCharacterEncoding("utf-8");
		// 获取模板
		Resource resource = new PathMatchingResourcePatternResolver()
			.getResource("classpath:templates/excels/processFlowCardTemplate.xlsx");
		// 这里URLEncoder.encode可以防止中文乱码
		ExcelWriter excelWriter = null;

		try {
			String fileName = URLEncoder.encode("工序流转卡", "UTF-8");

			response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
			// 这里 需要指定写用哪个class去写
			excelWriter = EasyExcel.write(response.getOutputStream()).withTemplate(resource.getInputStream()).build();

			TProcessFlowCard tProcessFlowCard = baseMapper.selectById(id);
			if (tProcessFlowCard != null) {
				HashMap<String, String> map = new HashMap<>();
				map.put("cardNumber", tProcessFlowCard.getCardNumber());
				map.put("moNumber", tProcessFlowCard.getMoNumber());
				map.put("materialCode", tProcessFlowCard.getMaterialCode());
				map.put("materialName", tProcessFlowCard.getMaterialName());
				map.put("specification", tProcessFlowCard.getSpecification());
				map.put("materialType", tProcessFlowCard.getMaterialType());
				map.put("surfaceTreatment", tProcessFlowCard.getSurfaceTreatment());
				map.put("quantity", String.valueOf(tProcessFlowCard.getQuantity()));
				map.put("unit", tProcessFlowCard.getUnit());
				map.put("lifecycle", tProcessFlowCard.getLifecycle());
				map.put("plannedStartTime", Objects.requireNonNull(tProcessFlowCard.getPlannedStartTime()).toString());
				map.put("plannedEndTime", Objects.requireNonNull(tProcessFlowCard.getPlannedEndTime()).toString());

				PageResult<TProcessInfoPageVO> infoPageVOPageResult = getDetailsById(tProcessFlowCard.getCardNumber());
				List<TProcessInfoPageVO> records = infoPageVOPageResult.getRecords();

				FillConfig rowConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
				WriteSheet processFlowCard = EasyExcel.writerSheet(0, "工序流转卡").head(TProcessInfoPageVO.class).build();

				excelWriter.fill(records, rowConfig, processFlowCard);
				excelWriter.fill(map, processFlowCard);

			}

		}
		catch (Exception e) {
			log.error("导出失败,{}", e.getMessage());
		}
		finally {
			// 千万别忘记finish 会帮忙关闭流
			if (excelWriter != null) {
				excelWriter.finish();
			}
		}

	}

	@Override
	public PageResult<TProcessInfoPageVO> getReportingForWorkByFlowCardNumber(String flowCardNumber) {
		return tProcessInfoService.getReportingForWorkByFlowCardNumber(flowCardNumber);
	}

	@Override
	public boolean getDataFromErp() {
		String redisKey = "KDSVCSessionId";
		String sessionId = (String) redisTemplate.opsForValue().get(redisKey);

		if (StringUtils.isBlank(sessionId)) {
			sessionId = loginERP();
			if (StringUtils.isBlank(sessionId)) {
				log.error("登录ERP失败，无法继续执行");
				return false;
			}
			redisTemplate.opsForValue().set(redisKey, sessionId, 2, TimeUnit.HOURS);
		}

		log.info("KDSVCSessionId: {}", sessionId);

		// 调用查询工序计划接口
		pullAllProcessPlans(sessionId);

		// 调用查询工序步骤接口
		pullAllProcessSteps(sessionId);

		// 如果后续有数据需要返回，这里实现；暂时返回空集合
		return true;
	}

	@Override
	public TProcessFlowCard getByProcessCardNumber(String processCardNumber) {
		return baseMapper.selectOne(
				new LambdaQueryWrapper<TProcessFlowCard>().eq(TProcessFlowCard::getCardNumber, processCardNumber));
	}

	@Override
	public boolean getDataFromErpByMo(String flowCardNumber) {

		String redisKey = "KDSVCSessionId";
		String sessionId = (String) redisTemplate.opsForValue().get(redisKey);

		if (StringUtils.isBlank(sessionId)) {
			sessionId = loginERP();
			if (StringUtils.isBlank(sessionId)) {
				log.error("登录ERP失败，无法继续执行");
				return false;
			}
			redisTemplate.opsForValue().set(redisKey, sessionId, 2, TimeUnit.HOURS);
		}

		log.info("KDSVCSessionId: {}", sessionId);

		// 调用查询工序计划接口
		Integer count = pullByFlowCardNumberProcessPlans(sessionId, flowCardNumber);

		if (count == 0) {
			return false;
		}

		// 调用查询工序步骤接口
		pullAllProcessSteps(sessionId);

		// 如果后续有数据需要返回，这里实现；暂时返回空集合
		return true;
	}

	private Integer pullByFlowCardNumberProcessPlans(String sessionId, String flowCardNumber) {
		return getProcessPlanByFlowCardNumber(sessionId, flowCardNumber);
	}

	public void pullAllProcessPlans(String sessionId) {
		String redisKey = "SFC_OperationPlanning:startRow";
		String maxFidKey = "SFC_OperationPlanning:maxFid";
		Integer row = (Integer) redisTemplate.opsForValue().get(redisKey);
		Integer fidValue = (Integer) redisTemplate.opsForValue().get(maxFidKey);
		if (row == null) {
			row = 0;
		}

		int batchSize = 100;
		Integer resultCount;
		int maxLoops = 1000;
		int currentLoop = 0;

		do {
			resultCount = getObtainProcessPlanChat(sessionId, row, batchSize, fidValue);
			row += resultCount;
			currentLoop++;
		}
		while (resultCount == batchSize && currentLoop < maxLoops);

		redisTemplate.opsForValue().set(redisKey, row);
	}

	public void pullAllProcessSteps(String sessionId) {
		String redisKey = "SFC_OperationPlanning:cardNumberTask";
		String failedKey = "SFC_OperationPlanning:cardNumberTask:failed";
		String value;
		String cardNumber;

		do {
			value = (String) redisTemplate.opsForList().leftPop(redisKey);
			if (value != null) {
				try {
					JSONObject jsonObject = JSONObject.parseObject(value);
					cardNumber = jsonObject.getString("cardNumber");
					boolean success = getProcessInfo(sessionId, cardNumber);
					if (!success) {
						log.warn("处理失败，放入失败队列: {}", value);
						redisTemplate.opsForList().rightPush(failedKey, value);
					}
				}
				catch (Exception e) {
					log.error("处理卡号 {} 时发生异常，已放入失败队列：", value, e);
					redisTemplate.opsForList().rightPush(failedKey, value);
				}
			}
		}
		while (value != null);
	}

	private String loginERPOld() {

		String result;

		long timestamp = System.currentTimeMillis() / 1000;
		// 数据中心ID
		String dbId = "6719f6e1cdd99e";
		// 用户名称
		String userName = "dev";
		// 第三方系统应用Id
		String appId = "295388_0Z7OxwhL7OlV2++u615D0Y+r1MQV2AmG";
		// 第三方系统应用秘钥
		String appSecret = "62a6bf84c82d4cd68618512bbe0299e2";
		// 语言ID
		Integer lcid = 2052;

		// 将账套ID、用户名、应用ID、应用秘钥、时间戳 放到数组里面
		String[] arr = new String[] { dbId, userName, appId, appSecret, String.valueOf(timestamp) };
		// 生成签名信息
		String sign = ErpSign.getSha256(arr);

		List<String> list = Arrays.asList(dbId, userName, appId, String.valueOf(timestamp), sign, String.valueOf(lcid));

		HashMap<String, List<String>> paramMap = new HashMap<>();
		paramMap.put("parameters", list);
		String param = JSONObject.toJSONString(paramMap);

		try {
			result = http.postJsonParam(HOST + LOGIN_URI, param);

			log.info("登录ERP结果,{}", result);

			JSONObject jo = JSONObject.parseObject(result);

			Integer LoginResultType = jo.getInteger("LoginResultType");

			if (LoginResultType != null && LoginResultType == 1) {

				String KDSVCSessionId = jo.getString("KDSVCSessionId");

				log.info("登录ERP成功,{}", result);

				return KDSVCSessionId;
			}
		}
		catch (IOException e) {
			log.error("登录ERP失败,{}", e.getMessage());
		}

		return null;
	}

	private String loginERP() {
		long timestamp = System.currentTimeMillis() / 1000;

		// 1. 生成签名
		String[] signArr = { erpConfig.getDbId(), erpConfig.getUserName(), erpConfig.getAppId(),
				erpConfig.getAppSecret(), String.valueOf(timestamp) };
		String sign = ErpSign.getSha256(signArr);

		// 2. 构造请求参数
		List<String> paramList = Arrays.asList(erpConfig.getDbId(), erpConfig.getUserName(), erpConfig.getAppId(),
				String.valueOf(timestamp), sign, String.valueOf(erpConfig.getLcid()));

		Map<String, List<String>> paramMap = new HashMap<>();
		paramMap.put("parameters", paramList);
		String requestJson = JSONObject.toJSONString(paramMap);

		// 3. 发起请求
		try {
			String result = http.postJsonParam(erpConfig.getHost() + erpConfig.getLoginUri(), requestJson);
			log.info("ERP 登录响应: {}", result);

			JSONObject json = JSONObject.parseObject(result);
			if (json.getInteger("LoginResultType") == 1) {
				String sessionId = json.getString("KDSVCSessionId");
				log.info("登录 ERP 成功，SessionId: {}", sessionId);
				return sessionId;
			}
			else {
				log.warn("登录 ERP 失败，返回: {}", result);
			}
		}
		catch (IOException e) {
			log.error("ERP 登录请求异常: {}", e.getMessage(), e);
		}

		return null;
	}

	/**
	 * 获取工序计划
	 */
	private Integer getObtainProcessPlanChat(String KDSVCSessionId, Integer startRow, Integer batchSize, Integer fId) {

		List<Map<String, Object>> conditionList = new ArrayList<>();

		// 1. 构建查询条件
		Map<String, Object> condition = new LinkedHashMap<>();
		condition.put("Left", "(");
		condition.put("FieldName", "FDocumentStatus");
		condition.put("Compare", "=");
		condition.put("Value", "C");
		condition.put("Right", ")");
		condition.put("Logic", "");

		if (fId != null) {
			condition.put("Logic", "AND");
			Map<String, Object> condition2 = new LinkedHashMap<>();
			condition2.put("Left", "(");
			condition2.put("FieldName", "FID");
			condition2.put("Compare", ">");
			condition2.put("Value", fId);
			condition2.put("Right", ")");
			condition2.put("Logic", "");
			conditionList.add(condition2);
		}

		conditionList.add(condition);

		// 2. 构建查询字段
		String FieIdKeys = "FID,FBillNo,FMONumber,FProductId.FNumber,FProductName,FProSpecification,FMOQty,FMOUnitId.FName,FPlanStartTime,FPlanFinishTime";

		// 3. 获取ERP数据
		String erpData = getErpDataList(KDSVCSessionId, "SFC_OperationPlanning", FieIdKeys, conditionList, null, null,
				String.valueOf(batchSize), "FID ASC");

		if (StringUtils.isBlank(erpData)) {
			return 0;
		}

		// 4. 解析JSON数据
		ObjectMapper mapper = new ObjectMapper();
		mapper.registerModule(new JavaTimeModule());
		mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
		mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

		List<TPrdMoVO> list;
		try {
			list = mapper.readValue(erpData, new TypeReference<List<TPrdMoVO>>() {
			});
		}
		catch (JsonProcessingException e) {
			throw new RuntimeException("解析ERP数据失败", e);
		}

		// 5. 过滤有效数据并分组
		List<TPrdMoVO> validList = list.stream()
			.filter(t -> StringUtils.isNotBlank(t.getFBillNo()))
			.collect(Collectors.toList());

		if (validList.isEmpty()) {
			return 0;
		}

		// 6. 批量查询已存在的数据
		List<Long> fIds = validList.stream().map(TPrdMoVO::getFId).collect(Collectors.toList());

		Map<Long, TProcessFlowCard> existingCards = baseMapper
			.selectList(new LambdaQueryWrapper<TProcessFlowCard>().in(TProcessFlowCard::getFId, fIds))
			.stream()
			.collect(Collectors.toMap(TProcessFlowCard::getFId, Function.identity()));

		// 7. 准备批量插入和更新的数据
		List<TProcessFlowCard> toInsert = new ArrayList<>();
		List<TProcessFlowCard> toUpdate = new ArrayList<>();

		validList.forEach(t -> {
			TProcessFlowCard card = new TProcessFlowCard();
			card.setFId(t.getFId());
			card.setCardNumber(t.getFBillNo());
			card.setMoNumber(t.getFmoNumber());
			card.setMaterialCode(t.getProductNumber());
			card.setMaterialName(t.getFProductName());
			card.setSpecification(t.getFProSpecification());
			card.setQuantity(t.getFmoQty());
			card.setUnit(t.getFmoUnitIdFName());
			card.setPlannedStartTime(t.getFPlanStartTime());
			card.setPlannedEndTime(t.getFPlanFinishTime());

			if (existingCards.containsKey(t.getFId())) {
				card.setId(existingCards.get(t.getFId()).getId());
				toUpdate.add(card);
			}
			else {
				toInsert.add(card);
			}
		});

		// 8. 批量操作
		if (!toInsert.isEmpty()) {
			saveBatch(toInsert);
		}
		// 暂时预留跟新操作
		/*
		 * if (!toUpdate.isEmpty()) { updateBatchById(toUpdate); }
		 */

		// 在解析完list后添加以下代码
		Optional<Long> maxFid = list.stream().map(TPrdMoVO::getFId).max(Comparator.naturalOrder());

		if (maxFid.isPresent()) {
			log.info("最大的FID是: " + maxFid.get());
			// 可以保存这个值用于后续处理
			Long maxFidValue = maxFid.get();
			Integer historyMaxFidValue = (Integer) redisTemplate.opsForValue().get("SFC_OperationPlanning:maxFid");
			if (historyMaxFidValue == null || maxFidValue > historyMaxFidValue) {
				redisTemplate.opsForValue().set("SFC_OperationPlanning:maxFid", maxFidValue);
			}
		}
		else {
			log.info("列表中没有数据");
		}

		if (!toInsert.isEmpty()) {
			List<String> cardJsonList = toInsert.stream().map(entry -> {
				Map<String, String> jsonMap = new HashMap<>();
				jsonMap.put("cardNumber", entry.getCardNumber());
				return JSON.toJSONString(jsonMap);
			}).collect(Collectors.toList());

			redisTemplate.opsForList().rightPushAll("SFC_OperationPlanning:cardNumberTask", cardJsonList);
		}

		return validList.size();
	}

	/**
	 * 获取工序计划
	 */
	private Integer getProcessPlanByFlowCardNumber(String KDSVCSessionId, String flowCardNumber) {

		List<Map<String, Object>> conditionList = new ArrayList<>();

		// 1. 构建查询条件
		Map<String, Object> condition = new LinkedHashMap<>();
		condition.put("Left", "(");
		condition.put("FieldName", "FDocumentStatus");
		condition.put("Compare", "=");
		condition.put("Value", "C");
		condition.put("Right", ")");
		condition.put("Logic", "");

		if (StringUtils.isNotBlank(flowCardNumber)) {
			condition.put("Logic", "AND");
			Map<String, Object> condition2 = new LinkedHashMap<>();
			condition2.put("Left", "(");
			condition2.put("FieldName", "FMONumber");
			condition2.put("Compare", "=");
			condition2.put("Value", flowCardNumber);
			condition2.put("Right", ")");
			condition2.put("Logic", "");
			conditionList.add(condition2);
		}

		conditionList.add(condition);

		// 2. 构建查询字段
		String FieIdKeys = "FID,FBillNo,FMONumber,FProductId.FNumber,FProductName,FProSpecification,FMOQty,FMOUnitId.FName,FPlanStartTime,FPlanFinishTime";

		// 3. 获取ERP数据
		String erpData = getErpDataList(KDSVCSessionId, "SFC_OperationPlanning", FieIdKeys, conditionList, null, null,
				null, "FID ASC");

		if (StringUtils.isBlank(erpData)) {
			return 0;
		}

		// 4. 解析JSON数据
		ObjectMapper mapper = new ObjectMapper();
		mapper.registerModule(new JavaTimeModule());
		mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
		mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

		List<TPrdMoVO> list;
		try {
			list = mapper.readValue(erpData, new TypeReference<List<TPrdMoVO>>() {
			});
		}
		catch (JsonProcessingException e) {
			throw new RuntimeException("解析ERP数据失败", e);
		}

		// 5. 过滤有效数据并分组
		List<TPrdMoVO> validList = list.stream()
			.filter(t -> StringUtils.isNotBlank(t.getFBillNo()))
			.collect(Collectors.toList());

		if (validList.isEmpty()) {
			return 0;
		}

		// 6. 批量查询已存在的数据
		List<Long> fIds = validList.stream().map(TPrdMoVO::getFId).collect(Collectors.toList());

		Map<Long, TProcessFlowCard> existingCards = baseMapper
			.selectList(new LambdaQueryWrapper<TProcessFlowCard>().in(TProcessFlowCard::getFId, fIds))
			.stream()
			.collect(Collectors.toMap(TProcessFlowCard::getFId, Function.identity()));

		// 7. 准备批量插入和更新的数据
		List<TProcessFlowCard> toInsert = new ArrayList<>();
		List<TProcessFlowCard> toUpdate = new ArrayList<>();

		validList.forEach(t -> {
			TProcessFlowCard card = new TProcessFlowCard();
			card.setFId(t.getFId());
			card.setCardNumber(t.getFBillNo());
			card.setMoNumber(t.getFmoNumber());
			card.setMaterialCode(t.getProductNumber());
			card.setMaterialName(t.getFProductName());
			card.setSpecification(t.getFProSpecification());
			card.setQuantity(t.getFmoQty());
			card.setUnit(t.getFmoUnitIdFName());
			card.setPlannedStartTime(t.getFPlanStartTime());
			card.setPlannedEndTime(t.getFPlanFinishTime());

			if (existingCards.containsKey(t.getFId())) {
				card.setId(existingCards.get(t.getFId()).getId());
				toUpdate.add(card);
			}
			else {
				toInsert.add(card);
			}
		});

		// 8. 批量操作
		if (!toInsert.isEmpty()) {
			saveBatch(toInsert);
		}

		if (!toInsert.isEmpty()) {
			List<String> cardJsonList = toInsert.stream().map(entry -> {
				Map<String, String> jsonMap = new HashMap<>();
				jsonMap.put("cardNumber", entry.getCardNumber());
				return JSON.toJSONString(jsonMap);
			}).collect(Collectors.toList());

			redisTemplate.opsForList().rightPushAll("SFC_OperationPlanning:cardNumberTask", cardJsonList);
		}

		return toInsert.size();
	}

	/**
	 * 获取工序列表
	 */
	private boolean getProcessInfo(String KDSVCSessionId, String flowCardNumber) {
		try {
			// 1. 构建查询条件
			Map<String, Object> condition = new LinkedHashMap<>();
			condition.put("Left", "(");
			condition.put("FieldName", "FBillNo");
			condition.put("Compare", "=");
			condition.put("Value", flowCardNumber);
			condition.put("Right", ")");
			condition.put("Logic", "AND");
			Map<String, Object> condition2 = new LinkedHashMap<>();
			condition2.put("Left", "(");
			condition2.put("FieldName", "FDocumentStatus");
			condition2.put("Compare", "=");
			condition2.put("Value", "C");
			condition2.put("Right", ")");
			condition2.put("Logic", "");

			List<Map<String, Object>> conditionList = new ArrayList<>();
			conditionList.add(condition);
			conditionList.add(condition2);

			// 2. 构建查询字段
			String fieldKeys = "FBillNo,FOperNumber,FProcessId.FName,FProcessId.FNumber,FOperQty,FOperUnitId.FName,FOperPlanStartTime,FOperPlanFinishTime,FActivity1BaseQty,FActivity2BaseQty";

			// 3. 获取ERP数据
			String erpData = getErpDataList(KDSVCSessionId, "SFC_OperationPlanning", fieldKeys, conditionList, null,
					null, null, "FOperNumber ASC");

			if (StringUtils.isBlank(erpData)) {
				log.info("ERP返回空数据，flowCardNumber={}", flowCardNumber);
				return true;
			}

			// 4. 解析JSON数据
			ObjectMapper mapper = new ObjectMapper();
			mapper.registerModule(new JavaTimeModule());
			mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
			mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

			List<TProcessInfoVO> list = mapper.readValue(erpData, new TypeReference<List<TProcessInfoVO>>() {
			});

			// 5. 过滤有效数据
			List<TProcessInfoVO> validList = list.stream()
				.filter(t -> StringUtils.isNotBlank(t.getFBillNo()))
				.filter(t -> t.getFOperNumber() != null)
				.collect(Collectors.toList());

			if (validList.isEmpty()) {
				log.info("无有效数据，flowCardNumber={}", flowCardNumber);
				return true;
			}

			// 6. 组装插入或更新数据
			List<TProcessInfo> toInsert = new ArrayList<>();
			List<TProcessInfo> toUpdate = new ArrayList<>();

			for (TProcessInfoVO t : validList) {
				TProcessInfo processInfo = new TProcessInfo();
				processInfo.setFlowCardNumber(t.getFBillNo());
				processInfo.setProcessSequence(t.getFOperNumber());
				processInfo.setProcessCode(t.getFProcessIdFNumber());
				processInfo.setProcessName(t.getFProcessIdFName());
				processInfo.setTotalQuantity(t.getFOperQty());
				processInfo.setSetupTime(new BigDecimal(t.getFActivity1BaseQty()));
				processInfo.setStandardTime(new BigDecimal(t.getFActivity2BaseQty()));

				boolean exists = tProcessInfoService.existsByKey(processInfo.getFlowCardNumber(),
						processInfo.getProcessSequence(), processInfo.getProcessCode());

				if (exists) {
					toUpdate.add(processInfo);
				}
				else {
					toInsert.add(processInfo);
				}
			}

			// 7. 批量保存
			if (!toInsert.isEmpty()) {
				tProcessInfoService.saveBatch(toInsert);
			}

			// 如需更新操作可启用：
			// if (!toUpdate.isEmpty()) {
			// tProcessInfoService.updateBatchById(toUpdate);
			// }

			return true;
		}
		catch (Exception e) {
			log.error("处理流程卡 [{}] 失败: {}", flowCardNumber, e.getMessage(), e);
			return false; // 一旦出错标记为失败，外部逻辑会将其丢入失败队列
		}
	}

	/**
	 * @param KDSVCSessionId sessionId
	 * @param FormId 表单ID
	 * @param FieldKeys 返回字段
	 * @param FilterString 过滤条件
	 * @param TopRowCount 返回条数
	 * @param StartRow 开始行索引
	 * @param Limit 最大行数，整型，不能超过10000
	 * @param OrderString 排序字段
	 * @return
	 */
	private String getErpDataList(String KDSVCSessionId, String FormId, String FieldKeys,
			List<Map<String, Object>> FilterString, String TopRowCount, String StartRow, String Limit,
			String OrderString) {

		String result = null;

		HashMap<String, String> headers = new HashMap<>();
		headers.put("Content-Type", "application/json");
		headers.put("kdservice-sessionid", KDSVCSessionId);

		HashMap<String, Object> paramMap = new HashMap<>();
		paramMap.put("FormId", FormId); // 必填
		HashMap<String, Object> data = new HashMap<>();
		data.put("FormId", FormId);
		data.put("FieldKeys", FieldKeys); // 返回字段
		data.put("FilterString", FilterString); // 过滤条件
		if (StringUtils.isNotBlank(TopRowCount)) {
			data.put("TopRowCount", TopRowCount); // 返回总行数
		}
		if (StringUtils.isNotBlank(StartRow)) {
			data.put("StartRow", StartRow); // 开始行索引
		}
		data.put("Limit", Limit); // 最大行数
		data.put("OrderString", OrderString); // 排序字段
		paramMap.put("data", data);

		log.info("参数,{}", JSONObject.toJSONString(paramMap));

		try {
			result = http.postJsonParam(HOST + GET_KEY_VALUE_JSON_URI, headers, JSONObject.toJSONString(paramMap));
			log.info("获取ERP结果,{}", result);
		}
		catch (IOException e) {
			log.error("获取ERP失败 {}", e.getMessage());
		}

		return result;
	}

}
